package com.niiwoo.civet.account.service.local.check.job;

import com.alibaba.fastjson.JSON;
import com.niiwoo.civet.account.service.local.check.job.api.CheckDetailService;
import com.niiwoo.civet.account.service.local.check.job.api.CheckRecordService;
import com.niiwoo.civet.account.service.local.check.job.api.NotifyService;
import com.niiwoo.civet.account.service.local.check.job.apiservice.AccountCheckingStatisticsService;
import com.niiwoo.civet.account.service.local.check.job.check.TypeDispatcher;
import com.niiwoo.civet.account.service.local.check.job.enums.CheckFileTypeEnum;
import com.niiwoo.civet.account.service.local.check.job.enums.TaskStepEnum;
import com.niiwoo.civet.account.service.local.check.job.parse.AccountCheckingParseTask;
import com.niiwoo.civet.account.service.local.check.job.properties.AccountCheckingProperties;
import com.niiwoo.civet.account.service.local.check.job.properties.Model;
import com.niiwoo.civet.account.service.local.check.job.util.SpringApplicationContextHolder;
import com.niiwoo.civet.account.service.local.check.job.util.ZipUtil;
import com.niiwoo.tripod.lanmao.properties.LanMaoProperties;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

@Slf4j
@SuppressWarnings({ "unchecked", "rawtypes" })
public abstract class AccountCheckJobFactory {

	//private final String JOB_CHECK_ACCOUNT = "JOB_CHECK_ACCOUNT";
	//private String jobKey;

	private Map<String, ParseTaskConfig<?>> parseTaskConfigs = new HashMap<String, ParseTaskConfig<?>>();

	private CheckRecordService checkRecordService;
	private NotifyService notifyService;

	private BlockingQueue<Runnable> queue;

	private Map<String, CheckDetailService> checkDetailServiceMap = new HashMap<String, CheckDetailService>();

	private ExecutorService parseExecutor;

	private AccountCheckJobFactory.BatchExceptionProcessor batchExceptionProcessor;
	private ExecutorService checkExecutor;

	private TypeDispatcher dispatcher;

	private Long recordId;

	private boolean isRecheck = false;

	private static Object lock = new Object();
	//private volatile static AtomicBoolean isRunning = new AtomicBoolean(false);

	protected AccountCheckingProperties properties;

	@Autowired
	private AccountCheckingStatisticsService accountCheckingStatisticsService;
	@Autowired
	private LanMaoProperties lanMapProperties;
	@Autowired
	private RedisTemplate redisTemplate;
	
	protected void registryParseTask(CheckFileTypeEnum checkFileTypeEnum, Class<?> cls) {
		ParseTaskConfig taskConfig = new ParseTaskConfig();
		taskConfig.setCheckFileTypeEnum(checkFileTypeEnum);
		taskConfig.setCls(cls);
		parseTaskConfigs.put(taskConfig.getCheckFileTypeEnum().getCode(), taskConfig);
	}
	
	protected void registryCheckTask(CheckFileTypeEnum checkFileTypeEnum, Class<?> cls) {
		if (!checkDetailServiceMap.containsKey(cls.getName())) {
			checkDetailServiceMap.put(cls.getName(), (CheckDetailService) SpringApplicationContextHolder.getBean(cls));
		}
	}

	protected void registryCheckRecordService(Class cls) {
		if (cls == null || !CheckRecordService.class.isAssignableFrom(cls)) { // 抛出异常

			return;
		}

		checkRecordService = (CheckRecordService) SpringApplicationContextHolder.getBean(cls);
		if (checkRecordService == null) {// 抛出异常

			return;
		}
	}

	protected void registryNotifyService(Class cls) {
		if (cls == null || !NotifyService.class.isAssignableFrom(cls)) { // 抛出异常

			return;
		}

		notifyService = (NotifyService) SpringApplicationContextHolder.getBean(cls);
		if (notifyService == null) {// 抛出异常

			return;
		}
	}

	protected void start(String fileDate) {
		long start = System.currentTimeMillis();
		TaskStepEnum step = TaskStepEnum.UNSTART;

		log.info("start account checking job. {}", fileDate);
		if (redisTemplate.hasKey(getJobKey(fileDate))) {
			log.info("check task is running. billDate:{},redis date:{}",
					fileDate,JSON.toJSONString(redisTemplate.opsForValue().get(getJobKey(fileDate))));
			return;
		}{
			Model model = new Model();
			model.setBillDate(fileDate);
			model.setStartDate(new Date());
			redisTemplate.opsForValue().set(getJobKey(fileDate), JSON.toJSONString(model));
			log.info("start account checking job.redis date:{}", JSON.toJSONString(model));
		}
		if (!init(fileDate)) {
			log.error("check record exists. {}", fileDate);
			return;
		}
		try {
			// 初始对账记录
			step = TaskStepEnum.UNDOWNLOAD;
			checkRecordService.update(TaskStepEnum.UNDOWNLOAD, properties.getCheckRecordId());

			// 1. 下载
			// 没有数据无法处理,重试：如果没有获取到内容则等待指定时间再重新下载
			downloadCheckFile(true);
			log.info("download checkfile from bankapi, path : {}", properties.getCheckZipFile());
			// 上传
			step = TaskStepEnum.UNUPLOAD;
			String downloadUrl = checkRecordService.uploadCheckFile(properties.getCheckZipFile(),
					properties.getCheckRecordId());
			log.info("upload checkfile to filesystem, downloadUrl : {}", downloadUrl);

			step = TaskStepEnum.UNZIP;
			checkRecordService.update(TaskStepEnum.UNZIP, properties.getCheckRecordId());

			// 2. 解压，解压到压缩包所在目录下
			ZipUtil.unzip(properties.getCheckZipFile());
			log.info("unzip success, checkfile path : {}", properties.getCheckZipFile());

			step = TaskStepEnum.UNSTORAGE;
			checkRecordService.update(TaskStepEnum.UNSTORAGE, properties.getCheckRecordId());

			// 3. 解析并存入数据库
			parse2db();

			log.info("parse checkfile and storage success.");

			step = TaskStepEnum.UNCHECK;
			checkRecordService.update(TaskStepEnum.UNCHECK, properties.getCheckRecordId());

			// 4. 查询数据并对账
			batchExceptionProcessor = new BatchExceptionProcessor(checkRecordService, properties);
			loadData2ThreadPool();
			batchExceptionProcessor.release();

			if (!batchExceptionProcessor.isSuccess) {
				log.error("batch save check exception fail");
				return;
			}

			log.info("check complete.");
			log.info("total {} record check error.", batchExceptionProcessor.getTotal());

			batchUpdateCheckDetailStatus((byte) 2); // 更新所有对账账单明细状态为已处理

			step = TaskStepEnum.UNSEND;
			// 比对结束
			checkRecordService.update(TaskStepEnum.UNSEND, properties.getCheckRecordId());

			// 5. 通知
			notifyService.notify(recordId, fileDate);

			accountCheckingStatisticsService.accountStatistics(properties.getCheckRecordId());
			accountCheckingStatisticsService.accountGuarantors(properties.getCheckRecordId());
			// 6. 获取对账结果是否对账成功
			//boolean isSuccess = checkRecordService.getCheckResult(recordId, fileDate);
			//boolean isSuccess = batchExceptionProcessor.getTotal() > 0 ? false : true;
			boolean isSuccess = checkRecordService.countExceptionRecordForHandleType(properties.getCheckRecordId()) == 0 ? true:false;
			//moveDataToHistoryDB();
			// 对账确认
			if (isSuccess) {
				step = TaskStepEnum.UNCONFIRM;
				
				// 删除对账成功的
				// deleteAllCheckSuccessBankOrder();
				
				checkRecordService.afterCheck(properties.getCheckDate(), properties.getCheckRecordId());

				checkRecordService.update(TaskStepEnum.SUCCESS, properties.getCheckRecordId());
				
				step = TaskStepEnum.SUCCESS;
			} else {
				 checkRecordService.update(TaskStepEnum.FAIL, properties.getCheckRecordId());
				
				step = TaskStepEnum.FAIL;
			}
		} catch (Exception e) {
			log.error("check fail, {}", e.getMessage(), e);
		} finally {
			release(fileDate);
			// 7. 删除zip包和解压后文件
			deleteCheckFiles();

			updateCheckRecordRemark(step, false);
		}

		log.info("total cost time : {}", (System.currentTimeMillis() - start));
	}

	private void deleteAllCheckSuccessBankOrder() {
		Iterator<CheckDetailService> it = checkDetailServiceMap.values().iterator();
		CheckDetailService checkDetailService;
		while (it.hasNext()) {
			checkDetailService = it.next();
			checkDetailService.deleteAllCheckSuccessBankOrder(properties.getCheckRecordId());
		}
	}

	public static class BatchExceptionProcessor {
		private List<Object> list;

		private int total = 0;

		private ExecutorService bexpes;

		private CheckRecordService checkRecordService;

		private boolean isSuccess = true;

		private AccountCheckingProperties properties;

		public BatchExceptionProcessor(CheckRecordService checkRecordService, AccountCheckingProperties properties) {
			this.checkRecordService = checkRecordService;
			this.properties = properties;
			list = new ArrayList<Object>();
			bexpes = Executors.newFixedThreadPool(3);
		}

		public boolean isSuccess() {
			return isSuccess;
		}

		public int getTotal() {
			return total;
		}

		/**
		 * 多个check线程同时将异常账单信息扔到异常队列中，每
		 * 
		 * @param obj
		 */
		public synchronized void batchExceptionDispatch(Object obj) {
			if (total > 0 && total % properties.getBatch2dbCapacity() == 0) {
				final List<Object> tmp = list;
				bexpes.execute(new Runnable() {
					public void run() {
						try {
							checkRecordService.batchSaveCheckException(tmp);
						} catch (Exception e) {
							log.error("batch save check exception fail, {}", e.getMessage(), e);
							isSuccess = false;
						}
					}
				});

				list = new ArrayList<Object>();
			}

			total++;
			list.add(obj);
		}

		public void release() {
			bexpes.shutdown();
			while (true) {
				if (bexpes.isTerminated()) { // 已经将任务全部完成 isCompleteCheck &&
					break;
				}

				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
				}
			}

			// 等所有对账线程都执行完成再处理最有一批异常账单数据入库
			if (list != null && !list.isEmpty()) {
				try {
					checkRecordService.batchSaveCheckException(list);
				} catch (Exception e) {
					log.error("batch save check exception fail, {}", e.getMessage(), e);
					isSuccess = false;
				}
			}
		}
	}

	private void updateCheckRecordRemark(TaskStepEnum step, boolean isRecheck) {
		checkRecordService.updateLastStepRemark(step, properties.getCheckRecordId(), isRecheck);
	}

	private void release(String fileDate) {
		if (parseExecutor != null && !parseExecutor.isShutdown()) {
			parseExecutor.shutdownNow();
		}

		if (checkExecutor != null && !checkExecutor.isShutdown()) {
			checkExecutor.shutdownNow();
		}

		//isRunning.set(false);
		redisTemplate.delete(getJobKey(fileDate));
	}

	public abstract void initProperties();

	public abstract void registry();

	private boolean init(String fileDate) {
		return init(fileDate, null, false, false);
	}

	protected boolean init(String fileDate, Long checkRecordId, boolean fromHandler, boolean isReloadData) {
		initProperties();

		registry();

		mergeLoadService();

		properties.setCheckDate(fileDate);
		properties.setReloadData(isReloadData);

		if (!fromHandler) {
			recordId = checkRecordService.findCheckRecord(fileDate);
			if (recordId != null && recordId > 0)
				return false;

			recordId = checkRecordService.save(TaskStepEnum.UNSTART, fileDate);
		} else {
			if (checkRecordId != null) {
				recordId = checkRecordService.findCheckRecord(checkRecordId);
			}

			if (recordId == null && fileDate != null && !"".equals(fileDate)) {
				recordId = checkRecordService.findCheckRecord(fileDate);
			}

			if (recordId == null)
				return false;

			isRecheck = true;
		}

		properties.setCheckRecordId(recordId);

		parseExecutor = Executors.newFixedThreadPool(parseTaskConfigs.size(), new ThreadFactory() {
			private AtomicInteger atomicInteger = new AtomicInteger(1);

			public Thread newThread(Runnable r) {
				return new Thread(r, "account-check-thread-" + atomicInteger.getAndIncrement());
			}
		});

		dispatcher = new TypeDispatcher(properties);

		queue = new LinkedBlockingQueue<Runnable>(properties.getQueueLoadDataLimit());
		checkExecutor = new ThreadPoolExecutor(properties.getCheckThreadNum(), properties.getCheckThreadNum(), 3000,
				TimeUnit.MILLISECONDS, queue, new ThreadFactory() {
					private AtomicInteger atomicInteger = new AtomicInteger(1);

					public Thread newThread(Runnable r) {
						return new Thread(r, "account-check-thread-" + atomicInteger.getAndIncrement());
					}
				});

		return true;
	}

	private void parse2db() throws Exception {
		Iterator<ParseTaskConfig<?>> parseTasks = parseTaskConfigs.values().iterator();
		ParseTaskConfig parseTask;
		Map<String, Future<Boolean>> resultMap = new HashMap<String, Future<Boolean>>();
		Future<Boolean> result;
		while (parseTasks.hasNext()) {
			parseTask = parseTasks.next();
			log.info("parse service {} start.", parseTask.getCheckFileTypeEnum().getName());

			// 重新对账 && 不需要重新解析数据 && 对账文件数据还没有入库
			if (isRecheck && !properties.isReloadData() && checkRecordService
					.checkParseTask(parseTask.getCheckFileTypeEnum().getCode(), properties.getCheckDate())) {
				continue;
			}

			result = parseExecutor.submit(new AccountCheckingParseTask(parseTask.getCheckFileTypeEnum(),
					parseTask.getCls(), dispatcher, properties));

			resultMap.put(parseTask.getCheckFileTypeEnum().getCode(), result);
		}

		parseExecutor.shutdown();
		while (true) {
			if (parseExecutor.isTerminated()) { // 已经将任务全部完成
				break;
			}

			try {
				Thread.sleep(3000);
			} catch (InterruptedException e) {
				log.error(e.getMessage(), e);
			}
		}

		log.info("all in db.");

		// 解析入库之后添加对应的解析入库任务记录
		Iterator<String> it = resultMap.keySet().iterator();
		String checkType;
		boolean parseResult = true;
		while (it.hasNext()) {
			checkType = it.next();

			if (!resultMap.get(checkType).get()) {
				parseResult = false;
			}

			checkRecordService.saveParseTask(checkType, properties.getCheckDate(), resultMap.get(checkType).get());
		}

		if (!parseResult) {
			throw new RuntimeException("parse checkfile error.");
		}
	}

	/*private void moveDataToHistoryDB() throws Exception{
		log.info("start data move to history table in database");
		Iterator<CheckDetailService> it = checkDetailServiceMap.values().iterator();
		CheckDetailService checkDetailService;
		while (it.hasNext()) {
			checkDetailService = it.next();
			log.info("check service {} start.", checkDetailService.getClass().getSimpleName());
			checkDetailService.moveDataToHistory(properties.getCheckRecordId());
		}
		log.info("end data move to history table in database");
	}*/

	private void mergeLoadService() {
		Iterator<ParseTaskConfig<?>> it = parseTaskConfigs.values().iterator();
		ParseTaskConfig parseTaskConfig;
		while (it.hasNext()) {
			parseTaskConfig = it.next();

			if (!checkDetailServiceMap.containsKey(parseTaskConfig.getCls().getName())) {
				checkDetailServiceMap.put(parseTaskConfig.getCls().getName(),
						(CheckDetailService) SpringApplicationContextHolder.getBean(parseTaskConfig.getCls()));
			}
		}
	}

	private void loadData2ThreadPool() {
		Iterator<CheckDetailService> it = checkDetailServiceMap.values().iterator();
		CheckDetailService checkDetailService;
		int page;
		List list = null;
		while (it.hasNext()) {
			checkDetailService = it.next();
			log.info("check service {} start.", checkDetailService.getClass().getSimpleName());
			page = 1;

			while (true) {
				if (queue.size() < (properties.getLoadDataLimit() - properties.getCheckThreadNum())) {
					list = checkDetailService.load(properties.getCheckRecordId(), page, properties.getLoadDataLimit());
					if (list == null || list.isEmpty()) {
						log.info("{} load data is null.", checkDetailService.getClass());
						break;
					}

					for (Object obj : list) {
						checkExecutor.execute(new CheckTask(obj, checkDetailService));
					}

					if (list.size() < properties.getLoadDataLimit()) {
						break;
					}

					page++;
				} else {
					try {
						Thread.sleep(properties.getLoadDataSleepTime()); // 如果任务队列中的任务数量没有小于阈值则休眠3秒钟
					} catch (InterruptedException e) {
						log.error(e.getMessage(), e);
					}
				}
			}
		}

		// 如果没有完成比对工作则一直休眠
		checkExecutor.shutdown();
		while (true) {
			if (checkExecutor.isTerminated()) { // 已经将任务全部完成 isCompleteCheck &&
				break;
			}

			try {
				Thread.sleep(3000);
			} catch (InterruptedException e) {
				log.error(e.getMessage(), e);
			}
		}

		log.info("all record is checked.");
	}

	protected void recheck(Long checkRecordId, String fileDate, boolean isReloadData) {
		long start = System.currentTimeMillis();

		TaskStepEnum result = TaskStepEnum.UNSTART;
		if (redisTemplate.hasKey(getJobKey(fileDate))) {
			log.info("check task is running. {}", fileDate);
			return;
		}else {
			Model model = new Model();
			model.setBillDate(fileDate);
			model.setStartDate(new Date());
			redisTemplate.opsForValue().set(getJobKey(fileDate),JSON.toJSONString(model));
			log.info("recheck task is running.{},redis date:{}",fileDate,JSON.toJSONString(model));
		}

		if (!init(fileDate, checkRecordId, true, isReloadData)) {
			log.error("recheck unknown checkrecord. {}", fileDate);
			return;
		}
		try {
			TaskStepEnum step = checkRecordService.findTaskStep(recordId);

			if (TaskStepEnum.SUCCESS.getCode().equals(step.getCode())) {
				log.error("check task is complete and result is good, {}", fileDate);
				return;
			}

			result = step;
			switch (step) {
			case UNSTART:
				Long recordId = checkRecordService.save(TaskStepEnum.UNSTART, fileDate);
				properties.setCheckRecordId(recordId);
			case UNDOWNLOAD:
			case UNUPLOAD:
			case UNZIP: // 未下载、未上传、未解压
			case UNSTORAGE:
				result = TaskStepEnum.UNDOWNLOAD;
				if (step == TaskStepEnum.UNDOWNLOAD || step == TaskStepEnum.UNUPLOAD) {
					// 增加下载逻辑（存管银行接口）
					downloadCheckFile(true);
					// 增加上传逻辑
				} else {
					// 增加下载逻辑（文件服务器），现阶段都直接从存管银行下载，防止数据变更
					downloadCheckFile(true);
				}
				
				log.info("download checkfile from bankapi, path : {}", properties.getCheckZipFile());

				result = TaskStepEnum.UNUPLOAD;
				String downloadUrl = checkRecordService.uploadCheckFile(properties.getCheckZipFile(), properties.getCheckRecordId());
				log.info("upload checkfile to filesystem, downloadUrl : {}", downloadUrl);

				result = TaskStepEnum.UNZIP;
				checkRecordService.update(TaskStepEnum.UNZIP, properties.getCheckRecordId());

				// 2. 解压，解压到压缩包所在目录下
				ZipUtil.unzip(properties.getCheckZipFile());
				log.info("unzip success, checkfile path : {}", properties.getCheckZipFile());

				result = TaskStepEnum.UNSTORAGE;
				checkRecordService.update(TaskStepEnum.UNSTORAGE, properties.getCheckRecordId());
				
				// 3. 解析并存入数据库
				properties.setReloadData(true); //重新对账且需要重新解析数据并入库，为保证数据一致性先删除数据库中所有存管账单信息
				parse2db();
				log.info("parse checkfile and storage success.");
				
				result = TaskStepEnum.UNCHECK;
				checkRecordService.update(TaskStepEnum.UNCHECK, properties.getCheckRecordId());
				
				break;
			case UNCHECK:
			case FAIL:
			default:
				result = TaskStepEnum.UNCHECK;
				checkRecordService.update(TaskStepEnum.UNCHECK, properties.getCheckRecordId());
				//checkRecordService.deleteAllCheckException(properties.getCheckRecordId()); // 删除之前所有的对账异常信息
				batchUpdateCheckDetailStatus((byte) 1); // 对账账单明细状态为待处理

				break;
			}
			
			checkRecordService.deleteAllCheckException(properties.getCheckRecordId()); // 删除之前所有的对账异常信息
			log.info("delete old exception record success.");

			// 4. 查询数据并对账
			batchExceptionProcessor = new BatchExceptionProcessor(checkRecordService, properties);
			loadData2ThreadPool();
			batchExceptionProcessor.release();

			if (!batchExceptionProcessor.isSuccess()) {
				log.error("batch save check exception fail");
				return;
			}

			log.info("check complete.");
			log.info("total {} record check error.", batchExceptionProcessor.getTotal());

			batchUpdateCheckDetailStatus((byte) 2);

			result = TaskStepEnum.UNSEND;
			// 比对结束
			checkRecordService.update(TaskStepEnum.UNSEND, properties.getCheckRecordId());
			// 通知
			notifyService.notify(recordId, fileDate);

			accountCheckingStatisticsService.accountStatistics(properties.getCheckRecordId());
			accountCheckingStatisticsService.accountGuarantors(properties.getCheckRecordId());
			// 6. 获取对账结果是否对账成功
//			boolean isSuccess = checkRecordService.getCheckResult(recordId, fileDate);
			//boolean isSuccess = batchExceptionProcessor.getTotal() > 0 ? false : true;
			boolean isSuccess = checkRecordService.countExceptionRecordForHandleType(properties.getCheckRecordId()) == 0 ? true:false;
			//moveDataToHistoryDB();
			// 对账确认
			if (isSuccess) {
				result = TaskStepEnum.UNCONFIRM;

				// 删除对账成功的
				// deleteAllCheckSuccessBankOrder();
				
				checkRecordService.afterCheck(properties.getCheckDate(), properties.getCheckRecordId());

				checkRecordService.update(TaskStepEnum.SUCCESS, properties.getCheckRecordId());
				
				result = TaskStepEnum.SUCCESS;
			} else {
				 checkRecordService.update(TaskStepEnum.FAIL, properties.getCheckRecordId());
				
				result = TaskStepEnum.FAIL;
			}
		} catch (Exception e) {
			log.error("recheck fail, {}", e.getMessage(), e);
		} finally {
			release(fileDate);

			// 删除zip包和解压后文件
			deleteCheckFiles();

			updateCheckRecordRemark(result, true);
		}

		log.info("total cost time : {}", (System.currentTimeMillis() - start));
	}

	private void batchUpdateCheckDetailStatus(byte status) {
		Iterator<CheckDetailService> it = checkDetailServiceMap.values().iterator();
		CheckDetailService checkDetailService;
		while (it.hasNext()) {
			checkDetailService = it.next();
			checkDetailService.batchUpdateCheckDetailStatus(properties.getCheckRecordId(), status);
		}
	}

	private void downloadCheckFile(boolean fromBankApi) throws Exception {
		int retryCount = 0;
		while (retryCount < properties.getDownloadRetryNum()) {
			try {
				checkRecordService.downloadCheckFile(fromBankApi, properties.getCheckRecordId(),
						properties.getCheckZipFile(), properties.getCheckDate());
				
				break;
			} catch (Exception e) {
				++retryCount; //重试次数+1
				log.error("download checkfile retry[{}], {}", retryCount, e.getMessage(), e); //打印异常
				
				if (retryCount >= properties.getDownloadRetryNum()) throw e; //达到最大尝试次数则抛出异常

				try { //休眠指定时间
					Thread.sleep(properties.getDownloadRetryPriod()); //默认30s
				} catch (Exception e2) {
				}
			}
		}
	}

	private void deleteCheckFiles() {
		String zipFile = properties.getCheckZipFile();

		File file = new File(zipFile);
		if (file.exists()) {
			try {
				FileUtils.forceDelete(file);
			} catch (IOException e) {
				log.error(e.getMessage(), e);
			}
		}

		File zipDir = new File(properties.getCheckFileDir());
		if (zipDir.exists()) {
			try {
				FileUtils.deleteDirectory(zipDir); // 删除解压目录
			} catch (IOException e) {
				log.error(e.getMessage(), e);
			}
		}
	}

	public class CheckTask implements Runnable {
		private CheckDetailService checkService;

		private Object t;

		public CheckTask(Object t, CheckDetailService checkService) {
			this.t = t;
			this.checkService = checkService;
		}

		public void run() {
			try {
				Object obj = checkService.check(t, properties.getCheckDate());

				if (obj != null)
					batchExceptionProcessor.batchExceptionDispatch(obj);
			} catch (Exception e) {
				log.error(e.getMessage(), e);
			}
		}
	}

	private String getJobKey(String billDate){
		String jobKey = "JOB_CHECK_ACCOUNT_BILL_DATE:"+billDate;
		return jobKey;
	}

	public class ParseTaskConfig<T> {
		private CheckFileTypeEnum checkFileTypeEnum;
		private Class<T> cls;

		public CheckFileTypeEnum getCheckFileTypeEnum() {
			return checkFileTypeEnum;
		}

		public void setCheckFileTypeEnum(CheckFileTypeEnum checkFileTypeEnum) {
			this.checkFileTypeEnum = checkFileTypeEnum;
		}

		public Class<T> getCls() {
			return cls;
		}

		public void setCls(Class<T> cls) {
			this.cls = cls;
		}
	}

}
